/*
 * Copyright (c) 2023 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <malloc.h>
#include <mc/core/application.h>
#include <mc/engine.h>
#include <mc/log.h>
#include "devmon.h"

static void run_malloc_trim()
{
    // 清理内存碎片，避免持续运行后大量碎片导致内存增长
    mallopt(M_ARENA_MAX, 1); // 1: 堆内存池最大数量
    mallopt(M_TRIM_THRESHOLD, 4 * 1024); // 4 * 1024 字节: 自动回收堆顶空闲内存给内核的阈值
    auto thread = std::make_unique<std::thread>([]() {
        while (true) {
            malloc_trim(0);
            std::this_thread::sleep_for(std::chrono::minutes(5)); // 每5分钟清理一次
        }
    });
    thread->detach();
}

int main(int argc, char** argv) {
    auto& app = mc::core::app();
    app.set_version("1.0.0");

    auto& factory = app.get_service_factory();
    factory.register_service<devmon::devmon_service>("devmon_service");

    try {
        run_malloc_trim();
        if (!app.initialize(argc, argv)) {
            elog("initialize devmon failed");
            return 0;
        }
        ilog("start devmon...");

        app.start();

        std::unordered_map<std::string, std::string> app_paths = {
            {"general_path", "/opt/bmc/apps/"}, {"customer_path", "/opt/bmc/extend/apps/"}};
        auto service = factory.create_service(
            "devmon_service", "bmc.kepler.devmon",
            {{"driver_path", "/opt/bmc/drivers/"}, {"app_paths", app_paths}});
        MC_ASSERT(service, "create devmon service failed");
        service->start();

        ilog("devmon started, press Ctrl+C to exit...");
        app.exec();

        ilog("devmon exit");
        return 0;
    } catch (const std::exception& e) {
        elog("error: ${error}", ("error", e.what()));
        return 1;
    }
}
